新增代码覆盖率解析

大致原理步骤:

1)编译阶段:加入编译选项 –fprofile-arcs –ftest-coverage。会在目标代码文件中加入对应的钩子,采集执行的统计来实现覆盖率的统计。

2)编译后会生成gcno,执行后生成gcda文件。

3)使用gcov,lcov可实现行覆盖、分支覆盖等计算,xx.info。

4)结合git diff生成的diff文件,计算新增代码覆盖率。

[UT/FT]

1. clone

|
|---UTCA ===> dev_zxsdr_v2.17.00.03
|
|---utility/sdr_utft ===> dev_zxsdr_v2.17.00.03


2. build & run

[yangpeng@yangpeng sdr_utft]$./cmp_utft_BuildAndRun.sh


3. add testcase

相关文件介绍:
(1)utility/sdr_utft/testcases/cmp/ut/testdata用于存放用例基线
(2)utility/sdr_utft/testcases/cmp/ut/testsuite/include source用于存放用例头文件、源文件

目前用例处理调试阶段,main工程不是包含source目录,如果新增用例源文件,需要在用例工程的CMakeList.txt对应增加。后期调试完毕,不需再加。

debug
utility/sdr_utft/build_tmp/lib# ./main --gtest_filter=*xxxxx* 可以执行制定用例,调试类似

[COV]

1. gcov gcov is a test coverage program.
compile option: -fprofile-arcs -ftest-coverage
|| ||
/ /
.gcda .gcno
run compile

xx.cpp.gcda yy.cpp.gcno

2. lcov lcov - a graphical GCOV front-end

ftcov.pl、NewCodeCoverData.ini

pha_entry.py

pha_dopatch.py

WORKSPACE


[PHA]

Jenkins Server: http://xxx.xxx.xxx.xxx:xxxx/ 

   1 #!/usr/bin/perl -w
   2 #modify 11.03 by ywq
   3 #modify 2015.03.12 by zlb
   4 #modify 2018.06.12 by lyj
   5 use Cwd;
   6 use Encode;
   7 use Date::Calc qw(:all);
   8 
   9 ##### 调试信息开关 ######
  10 my $gDebugMsg;
  11 
  12 #####################全局变量#####################
  13 my $Config_File = "CodeCoverCfg.ini";
  14 my $gCoverFile = "";
  15 my $gCodePath = "";
  16 my $gBuildCodePath = "";
  17 my $gNodeBase = "";
  18 my $gKeyWordsStr = "";
  19 my $gUpdateDateMethod = "weekly";
  20 my $gTestcasesStat = "";
  21 #log文件
  22 my $RecodResultFile = "";
  23 my $ReportHtmlFile = "";
  24 
  25 my $gCiHomePath = "";
  26 my $gCmakeBuildPath = "";
  27 my $gProjectPath = "";
  28 my $gMyVersion = "";
  29 
  30 
  31 my $gCiVersionCfgFile = ReadValueCfg("$Config_File", "DIFF_CONFIG", "CiVersionCfg");
  32 my $gDifFile = ReadValueCfg("$Config_File", "DIFF_CONFIG", "DifFile");
  33 my $gLcovFile = ReadValueCfg("$Config_File", "DIFF_CONFIG", "LcovFile");
  34 my $gBranchVersion = ReadValueCfg("$Config_File","DIFF_CONFIG","BranchVersion");
  35 my $gCodeVersion = ReadValueCfg("$Config_File","DIFF_CONFIG","CodeVersion");
  36 
  37 my $gIgnoreFile = ReadValueCfg("$Config_File", "IGNORE_FILE_CONFIG", "IgnoreFile");
  38 if (defined $gIgnoreFile){
  39     print "Ignore File list  [G]: ".$gIgnoreFile."
";
  40 }
  41 my $gIgnorelinesection = ReadValueCfg("$Config_File", "IGNORE_FILE_CONFIG", "Ignorelinesection");
  42 if (defined $gIgnorelinesection){
  43     print "Ignore line sect  [G]: ".$gIgnorelinesection."
";
  44 }
  45 my $gIgnorelineno = ReadValueCfg("$Config_File", "IGNORE_FILE_CONFIG", "Ignorelineno");
  46 if (defined $gIgnorelineno){
  47     print "Ignore line no    [G]: ".$gIgnorelineno."
";
  48 }
  49 
  50 my @gIgnoreArr = ();
  51 my @gIgnoreLineSection = ();
  52 my @gKeyWordsArr = ();
  53 
  54 my $Root = getcwd;
  55 chdir($Root);
  56 
  57 
  58 @gArray = ();
  59 #@gSArray = ();
  60 my $gArrayCount = 0;
  61 #my $gSArrayCount = 0;
  62 
  63 %gDiffFileLineHash = ();
  64 %gIgnoreLineHash = ();
  65 my $Content = "";#新增代码详细内容
  66 
  67 #分支覆盖
  68 my $gDecisionCount = 0;
  69 my $gDecisionCoverCount = 0;
  70 
  71 #记录当前时间
  72 my $gDateTimeNow = GetDateTime();
  73 my $gCurrDate = GetDate();
  74 
  75 #新增覆盖率
  76 my $gNewOutofNum = 0;
  77 my $gNewCoverRage = 0;
  78 my $gProjectCoverage = 0;
  79 
  80 #更新状态文件信息
  81 my $gGitPrevDate = 0;
  82 
  83 my $proj_stats="";
  84 my $all_stats="";
  85 
  86 my (%gLcovHash);
  87 
  88 ###########################################
  89 
  90 main(@ARGV);
  91 
  92 ###########################################
  93 
  94 sub main {
  95     my (@ARGV) = @_;
  96     my $Endtime = "";
  97     my $html_begin="";
  98     my $html_end="";
  99     my $errorlogfile = "errorlog.txt";
 100     open($errorlogfile, "> $errorlogfile");
 101 
 102     if($ARGV[0] eq "") {
 103         print $errorlogfile("Usage: ftcov.pl INI_SECTION [project_path [build_debug_path [admin_home_path]]]
");
 104         print $errorlogfile("  INI_SECTION: $Config_File file section.
  project_path: project path, like .../dev_21703/
build_debug_path: cmakek build path, like .../BRS_EM/cmake-debug-build/
admin_home_path: CI config home path, like /home/brs/");
 105         close($errorlogfile);
 106         return;
 107     } else {
 108         $gTestProject = $ARGV[0];
 109         $gdiffId      = $ARGV[1];
 110         $gbaseBranch  = $ARGV[2];
 111         print $gTestProject;
 112         print $gbaseBranch;
 113         print $gdiffId;
 114         #$gProjectPath = $ARGV[1];    #.../dev_21703/
 115         #$gProjectPath = "./../../../";    #.../dev_21703/
 116         #$gCmakeBuildPath = $ARGV[2]; #.../BRS_EM/cmake-build-debug
 117         #$gCiHomePath = $ARGV[3];     #/home/brs/
 118     }
 119 
 120     if (defined $gProjectPath) {
 121         #$gDifFile = $gProjectPath.$gDifFile;
 122         #$gMyVersion = $gProjectPath."/myversion";
 123 
 124         # These TWO vars rebuild 
 125         #$gBranchVersion
 126         #$gCodeVersion
 127         # BRSCI have some version config
 128         # read from these file
 129         ReadProjectCfgFromCiCfg();
 130     }
 131 
 132 
 133     if (ChkIniSection($Config_File,$gTestProject) == 0) {
 134         print "--------
";
 135         print "Error $Config_File,$gTestProject  not exist!
";
 136         print "--------
";
 137         close($errorlogfile);
 138         return;
 139     }else{
 140         print "--------
";
 141         print "Starting $Config_File,$gTestProject ...
";
 142         print "--------
";
 143     }
 144 
 145     if (GetProjectParameter($Config_File,$gTestProject) == 0){
 146         close($errorlogfile);
 147         return;
 148     }
 149 
 150     if (defined $gIgnoreFile) {
 151         @gIgnoreArr = split /;+/, $gIgnoreFile;
 152     }
 153     if (defined $gIgnorelinesection) {
 154         @gIgnoreLineSection = split /;+/, $gIgnorelinesection;
 155     }
 156 
 157     #输出文件
 158     $RecodResultFile = "$gTestProject".".txt";
 159     open($RecodResultFile, "> $RecodResultFile") || die("Could not open $RecodResultFile");
 160 
 161 
 162     $html_begin = '<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> </head> <body>';
 163     $html_end = '</body> </html>';
 164     $ReportHtmlFile = "$gTestProject".".html";
 165     open($ReportHtmlFile, ">:encoding(utf-8)","$ReportHtmlFile") || die("Could not open $ReportHtmlFile");
 166     print $ReportHtmlFile decode('gbk',"$html_begin");
 167 
 168     print $RecodResultFile("***********************************Start:$gDateTimeNow**********************************
");
 169     print $RecodResultFile("模块号:$gTestProject。
");
 170 
 171     UpdateDiffFile();
 172 
 173     changecovfile();
 174 
 175     CalcCovs();
 176 
 177     $Endtime = GetDateTime();
 178     print $RecodResultFile("***********************************End:$Endtime**********************************
");
 179 
 180 
 181     print $ReportHtmlFile decode('utf-8',"$html_end");
 182     close($RecodResultFile);
 183     close($ReportHtmlFile);
 184     close($errorlogfile);
 185 }
 186 
 187 sub PickCoverLine {
 188     my $fileHandle;
 189 
 190     if(-e $gCoverFile) {
 191         open($fileHandle, "$gCoverFile");
 192     } else {
 193         print $RecodResultFile("PickCoverLine : open $gCoverFile fail.
");
 194         return;
 195     }
 196 
 197     my $CurFile;
 198     my $PreFile = "";
 199     my $IgnoreLine = 0;
 200     my $IgnoreFunc = 0;
 201 
 202     my $space = "&nbsp;&nbsp;&nbsp;&nbsp;";
 203     my $color = "<font color=0x99FF size=6.5>";
 204     my $colorsect = "<font color=0x44AA size=4.5>";
 205     my $nextline = "<br>";
 206     my $font = "</font>";
 207     my $red = "RED";
 208     my $gray ="BLUE";
 209     my $black = "GREEN";
 210     my $nocover = "<font color=$red size=4>New Uncovered</font>";
 211     my $colorTF = "";
 212     my $statistics = "";
 213     my $linesectionbegin = 1;
 214     my $linesection = "";
 215 
 216     my $note_fir = "<font color=$red size=3>NOTE:The first column: Line numbers</font>";
 217     my $note_sec = "<font color=$red size=3>The Second column: Coverage(true first: + be coveraged,- not coveraged)</font>";  
 218     $Content = $Content.$nextline.$note_fir.$nextline;
 219     $Content = $Content.$nextline.$note_sec.$nextline;
 220 
 221     while(<$fileHandle>) {
 222         #文件比较开始
 223         if($_ =~ /^.+/(.+?),(d+),(d+),(d+),(.*)$/) {
 224             #    $1 文件名        $2 行号        
 225             #    $3 行总分支数    $4 覆盖分支数
 226             #    $5 覆盖信息
 227             #分析完的文件从hash中删除
 228             if(lc($1) ne $PreFile && exists $gDiffFileLineHash{$PreFile}) {
 229                 delete $gDiffFileLineHash{$PreFile};
 230                 $CurFile = "";
 231                 #当hash为空时停止循环
 232                 my $length = keys %gDiffFileLineHash;
 233                 if($length eq 0) {
 234                     last;
 235                 }
 236             }
 237             #如果当前文件名与前一个文件名不同
 238             if(lc($1) ne $PreFile && exists $gDiffFileLineHash{lc($1)}) {
 239                 #第一次的时候$PreFile不在hash表里
 240                 $FileBeginFlag = 1;
 241             }
 242             $PreFile = lc($1);
 243 
 244             if(exists $gDiffFileLineHash{lc($1)}) {
 245                 $CurFile = lc($1);
 246             } else {#如果不是要分析的文件,继续查找
 247                 next;
 248             }
 249 
 250             #根据文件名从哈希表中找到新增代码的起始行&&末行
 251             my @LineNoArray = @{$gDiffFileLineHash{$CurFile}};
 252 
 253             my $LineNoBegin = $LineNoArray[0];
 254             my $LineNoEnd = $LineNoArray[-1];
 255 
 256             #如果找到行号小于修改行号最小值,继续查找
 257             if($2<$LineNoBegin) {
 258                 next;
 259             }
 260             #如果找到行号大于修改行号最大值,结束查找
 261             if($2>$LineNoEnd) {
 262                 next;
 263             }
 264             foreach $LineNo (@LineNoArray) {
 265                 #如果找到行号小于当前修改行号,结束查找
 266                 if($2<$LineNo) {
 267                     last;
 268                 }
 269                 #如果当前修改行号为0,继续查找
 270                 if($LineNo==0) {
 271                     next;
 272                 }
 273                 #如果找到行号大于当前修改行号,继续查找
 274                 if($2>$LineNo) {
 275                     next;
 276                 }
 277 
 278                 #如果覆盖未TF,tf,更新LineCoverCount,更新数组中当前修改行号为0,避免重复计算
 279                 {
 280                     $gDecisionCount = $gDecisionCount + $3;
 281                     $gDecisionCoverCount = $gDecisionCoverCount + $4;
 282                     if ($4 eq "0") {
 283                         $colorTF = "<font color=$red size=4>($5)</font>";
 284                     }elsif ($4 eq $3) {
 285                         $colorTF = "<font color=$black size=4>($5)</font>";
 286                     }else {
 287                         $colorTF = "<font color=$gray size=4>($5)</font>";
 288                     }
 289 
 290                     my $colorString = $colorTF;
 291 
 292                     for($i = 0; $i < $gArrayCount; $i++) {
 293                         if(lc($gArray[$i][0]) eq lc($CurFile) && $gArray[$i][1] == $2) {
 294                             if($FileBeginFlag == 1) {
 295                                 $Content = $Content.$nextline.$color.$CurFile.$font.$nextline;
 296                                 $FileBeginFlag = 0;
 297                             }
 298 
 299                             if($linesectionbegin == 1) {
 300                                 $linesection = $gArray[$i][3];
 301                                 $Content = $Content.$colorsect.$linesection.$font.$nextline;
 302                                 $linesectionbegin = 0;
 303                             }elsif($linesection ne $gArray[$i][3]) {
 304                                 $linesection = $gArray[$i][3];
 305                                 $Content = $Content.$colorsect.$linesection.$font.$nextline;
 306                             }
 307 
 308                             $Content = $Content.$space.$LineNo.$space.$colorString.$space.$gArray[$i][2].$nextline;
 309 
 310                             last;
 311                         }
 312                     }
 313                 }
 314 
 315             }
 316         } else {
 317             next;
 318         }
 319     }
 320 
 321     close($fileHandle);
 322 }
 323 
 324 
 325 sub GetDiffFileInfo {
 326     my $fp;
 327     my($filename, $arrayflag) = @_;
 328 
 329     print "-----------------------
";
 330     if(-e $filename) {
 331         open($fp, "$filename");
 332         print "open $filename ok!
";
 333     }else {
 334         print "open $filename error!
";
 335         return;
 336     }
 337 
 338     my $CurFile = "";
 339     my $FilePath = "";
 340     my $LineString;
 341     my $LineCount = 0;
 342     my $hashflag = 0;
 343     my $catchbegin = 0;
 344     my $beginline = 0;
 345     my $continueline = 0;
 346     my $linesection = "";
 347     my $strtmp = "BRS_SECURITY";
 348     my $strtmpnull = "NULL";
 349     my $strtmpprintf = "rintf";
 350 
 351     if($arrayflag eq 0) {
 352         $hashflag = 0;
 353     }else {
 354         $hashflag = 1;
 355     }
 356 
 357     @tmp = ();
 358 
 359     PutIgnorelinenoInHash();
 360 
 361     while(<$fp>) {
 362         #文件比较开始一行一行比较
 363         if($_ =~ /^diffs--gits.+/(.+?.cpp)s*$/) {
 364             $CurFile = $1;
 365             $FilePath = $_;
 366         } elsif($_ =~ /^diffs--gits.+/(.+?.h)s*$/) {
 367             $CurFile = $1;
 368             $FilePath = $_;
 369         } elsif($_ =~ /^diffs--gits.+/(.+?.c)s*$/) {
 370             $CurFile = $1;
 371             $FilePath = $_;
 372             #print "path:$FilePath,file:$CurFile
"
 373         } elsif($_ =~ /^@@s.++(d+),(d+)s@@.*$/) {#增加或修改
 374             $LineCount = 0;
 375             $beginline = $1;
 376             $continueline = $1+$2;
 377             $linesection = "($beginline,$continueline)";
 378 
 379             #print "Diff file modify section: $linesection
";
 380         } elsif($_ =~ /^+s*$/) {#增加的空行。。。
 381             $LineCount++;
 382         } elsif($_ =~ /^s.*$/)  {#不变的任何行
 383             $LineCount++;
 384         } elsif($_ =~ /^---s(.+)$/) {#---行
 385             #print $1."
";
 386             next;
 387         } elsif($_ =~ /^+++s(.+)$/) {#+++行
 388             #print $1."
";
 389             next;
 390         } elsif($_ =~ /^+(.+)$/) {#增加修改的具体函数内容
 391             $tmp[0] = $CurFile;
 392             $tmp[1] = $beginline+$LineCount;
 393             $tmp[2] = $1;
 394             $tmp[3] = $linesection;
 395 
 396             $LineCount++;
 397 
 398             if (IsKeyWordsPath($FilePath) == 0) {
 399                 if (defined $gDebugMsg){
 400                     print "$CurFile : keywordpath ignored[$tmp[1],$tmp[3],$tmp[2]].
";
 401                 }
 402                 next;
 403             }elsif (IsIgnore($tmp[0],$tmp[3],$tmp[1]) == 1) {
 404                 if (defined $gDebugMsg){
 405                     print "$CurFile : ignore ignored[$tmp[1],$tmp[3],$tmp[2]].
";
 406                 }
 407                 next;
 408             }elsif ($1 =~ /$strtmp/) {
 409                 if (defined $gDebugMsg){
 410                     print "$CurFile : strtmp ignored[$tmp[1],$tmp[3],$tmp[2]].
";
 411                 }
 412                 next;
 413             }elsif ($1 =~ /$strtmpnull/) {
 414                 if (defined $gDebugMsg){
 415                     print "$CurFile : strtmpnull ignored[$tmp[1],$tmp[3],$tmp[2]].
";
 416                 }
 417                 next;
 418             }elsif ($1 =~ /$strtmpprintf/) {
 419                 if (defined $gDebugMsg){
 420                     print "$CurFile : strtmpprintf ignored[$tmp[1],$tmp[3],$tmp[2]].
";
 421                 }
 422                 next;
 423             }
 424 
 425             push @{$gDiffFileLineHash{$CurFile}}, $tmp[1];
 426 
 427             $gArray[$gArrayCount] = [$tmp[0], $tmp[1], $tmp[2],$tmp[3]];
 428             $gArrayCount++;
 429         } else {
 430             next;
 431         }
 432     }
 433 
 434     close($fp);
 435 }
 436 
 437 sub GetProjectParameter {
 438     my ($fileName,$Projectname) = @_;
 439 
 440     my $gSectionIgnoreFile;
 441 
 442     $gCoverFile = ReadValueCfg($fileName, $Projectname, "CoverFile");
 443     print "CoverResult file     : ".$gCoverFile."
";
 444 
 445     $gCodePath = ReadValueCfg($fileName, $Projectname, "CodePath");
 446     if (defined $gProjectPath){
 447         $gCodePath = $gProjectPath.$gCodePath;
 448     }
 449     print "Source code path     : ".$gCodePath."
";
 450 
 451     $gBuildCodePath = ReadValueCfg($fileName, $Projectname, "BuildCodePath");
 452     @gBuildCodePathArr = split /;+/, $gBuildCodePath;
 453     if (defined $gCmakeBuildPath){
 454         for ( $idx = 0; $idx < @gBuildCodePathArr; $idx ++){
 455             $gBuildCodePathArr[$idx] = $gCmakeBuildPath.$gBuildCodePathArr[$idx];
 456         }
 457     } elsif (defined $gProjectPath) {
 458         for ( $idx = 0; $idx < @gBuildCodePathArr; $idx ++){
 459             $gBuildCodePathArr[$idx] = $gProjectPath.$gBuildCodePathArr[$idx];
 460         }
 461     }
 462     print "Gcov parse code path : ".@gBuildCodePathArr."
";
 463 
 464     $gNodeBase = ReadValueCfg($fileName, $Projectname, "NodeBase");
 465     print $gNodeBase."
";
 466 
 467     $gUpdateDateMethod = ReadValueCfg($fileName, $Projectname, "UpdateDateMethod");
 468     print "FT update type       : ".$gUpdateDateMethod."
";
 469 
 470     $gSectionIgnoreFile = ReadValueCfg($fileName, $Projectname, "IgnoreFile");
 471     if (defined $gSectionIgnoreFile){
 472         $gIgnoreFile = $gIgnoreFile.";".$gSectionIgnoreFile;
 473         print "Ignore File list     : ".$gIgnoreFile."
";
 474     }
 475 
 476     $gKeyWordsStr = ReadValueCfg($fileName, $Projectname, "keywords");
 477     if (defined $gKeyWordsStr){
 478         print "FT Keyword list      : ".$gKeyWordsStr."
";
 479     }else {
 480         print "Error: not define keyswords!! You should add "keywords = all;".
";
 481         return 0;
 482     }
 483 
 484     $gTestcasesStat = ReadValueCfg($fileName, $Projectname, "TestcasesStat");
 485     if (defined $gTestcasesStat){
 486         print "TestCase stats path  : ".$gTestcasesStat."
";
 487     }
 488 
 489     if (defined $gKeyWordsStr){
 490         @gKeyWordsArr = split /;+/, $gKeyWordsStr;
 491     }
 492 
 493     return 1;
 494 }
 495 
 496 
 497 sub ChkIniSection {
 498     my($fileName, $labelName) = @_;
 499     my $value = 0;    
 500     my $fileHandle;
 501 
 502     if(-e $fileName) {
 503         open($fileHandle, "$fileName");
 504     }else {
 505         return;
 506     }
 507 
 508     while(defined($_ = <$fileHandle>)) {
 509         next if /^#/;   # 丢弃注释
 510         chomp;
 511         if(/^[.*]/){
 512             if(/[$labelName]/) {
 513                 $value = 1;    
 514                 last;
 515             }
 516         }
 517         next;
 518     }    
 519     close $fileHandle;
 520     return ($value);
 521 }
 522 
 523 
 524 #从配置文件中读取值类型的配置
 525 sub ReadValueCfg {
 526     my($fileName, $labelName, $keyName) = @_;
 527     my $isNeedLabel = 0;
 528     my $value;    
 529     my $fileHandle;
 530 
 531     if(-e $fileName) {
 532         open($fileHandle, "$fileName");
 533     }else {
 534         return;
 535     }
 536 
 537     while(defined($_ = <$fileHandle>)) {
 538         next if /^#/;   # 丢弃注释
 539         chomp;
 540 
 541         if ($isNeedLabel == 1){
 542             if(/^[.*]/){
 543                 # 进入另外一个段,退出
 544                 last;
 545             }
 546             if(!$isNeedLabel) {
 547                 next;
 548             }
 549             if(/$keyNames*=s*(.+);s*$/) {
 550                 $value = $1;    
 551                 last;
 552             }
 553         }else{
 554             if(/^[.*]/){
 555                 if(/[$labelName]/) {
 556                     $isNeedLabel = 1;
 557                 }
 558             }
 559             next;
 560         }
 561     }    
 562     close $fileHandle;
 563     return ($value);
 564 }
 565 
 566 
 567 sub GetDate {    
 568     ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
 569     $now = sprintf("%d-%02d-%02d",$year+1900,$mon+1,$mday);
 570     return $now;
 571 }
 572 
 573 sub GetDateTime {    
 574     ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
 575     $now = sprintf("%d-%02d-%02d %02d:%02d:%02d",$year+1900,$mon+1,$mday,$hour,$min,$sec);
 576     return $now;
 577 }
 578 
 579 
 580 sub CalcCovs {
 581     my $flag = 0;
 582     my $red = "RED";
 583     my $blue = "BLUE";
 584     my $str = "";
 585     my $CurPreNodefile;
 586 
 587     ParseTestCasesStat();
 588 
 589     GetDiffFileInfo($gDifFile, $flag);
 590 
 591     PickCoverLine();
 592 
 593     my $sum = $gDecisionCount;
 594     $gNewOutofNum = $sum;
 595     my $covercount = $gDecisionCoverCount;
 596     my $nocovercount = $sum - $covercount;
 597 
 598     my $total_cases_stat = "<font color=$blue size=5>Total TestCases:$all_stats</font><br>";
 599     my $per_project_stat = "<font color=$blue size=5>Project TestCases:$proj_stats</font><br>";
 600 
 601     if($gDecisionCount == 0) {
 602         $gNewCoverRage = 60;
 603         $Content = "<font color=$red size=5>The Branch of Code No Change,So New Code Coverage:60%(项目达标线)</font>"."<br>";
 604 
 605         if(defined $gTestcasesStat){
 606             if(-e $gTestcasesStat) {
 607                 $Content .= $total_cases_stat;
 608                 $Content .= $per_project_stat;
 609             }
 610         }
 611         $str = $gNewCoverRage;
 612     } else {
 613         $gNewCoverRage = ($gDecisionCoverCount)*100/($gDecisionCount);
 614         $str = substr(lc($gNewCoverRage), 0, 6);
 615 
 616         my $web_new     = "<font color=$blue size=5>Sum Of New Branch:$sum</font><br>";
 617         my $web_cover   = "<font color=$blue size=5>Covered Branch:$covercount</font><br>";
 618         my $web_uncover = "<font color=$blue size=5>UnCovered Branch:$nocovercount</font><br>";   
 619         my $web_newcov  = "<font color=$blue size=5>New Code Coverage:$str%</font><br>";
 620 
 621         if(defined $gTestcasesStat){
 622             if(-e $gTestcasesStat) {
 623                 $Content = $per_project_stat.$Content;
 624                 $Content = $total_cases_stat.$Content;
 625             }
 626         }
 627 
 628         $Content = $web_new.$Content;
 629         $Content = $web_cover.$Content;
 630         $Content = $web_uncover.$Content;
 631         $Content = $web_newcov.$Content;
 632     }
 633 
 634     if($Content ne "") {
 635         print $ReportHtmlFile decode('gbk',"$Content");
 636     }
 637 
 638     if($gDecisionCount == 0) {
 639         print $RecodResultFile("两个节点间分支数未变化,新增覆盖率为 ---.
");
 640     } else {
 641         print $RecodResultFile("新增覆盖率:$gNewCoverRage% ---(新增代码被覆盖分支数/新增代码总分支数).
");
 642         print $RecodResultFile("总的新增分支数:$sum,新增代码被覆盖分支数:$covercount,新增代码未覆盖分支数:$nocovercount.
");
 643     }
 644     
 645     if($gNewCoverRage < 60){
 646         print $RecodResultFile("新增覆盖率:未达项目线.
");
 647     }
 648                      
 649     print "-----------------------
";
 650     print "Total CHANGED branch count:".$gDecisionCount."
";
 651     print "-----------------------
";
 652 }
 653 
 654 my $FoundSameFile = 0;
 655 my $FoundSameKey = 0;
 656 my $linecount=0;
 657 
 658 sub merge_calc{
 659     my ($fileLine)=@_;
 660     my (%zero_hash);
 661     my (%branchHash);
 662     my (@tmpArr);
 663     my $tmp = 0;
 664     my $tmpBranch= {};
 665     $linecount += 1;
 666     # 新增加一个文件的分支数据
 667     if($fileLine =~ /^SF:(.*/([^/]+[a-zA-Z]))[^a-zA-Z]*$/) {
 668         #print "found file key:".$1.",".$2.",".$linecount."
";
 669         # 清空
 670         $branchHash = {};
 671         # 置位
 672         $FoundSameKey = 0;
 673         $FoundSameFile = 0;
 674        
 675         if (exists $gLcovHash->{$2}){
 676             @tmpArr = @{$gLcovHash->{$2}};
 677             if ($#tmpArr >= 0){
 678                 $FoundSameKey = 1;
 679                 #print "found same key ($#tmpArr): $tmpArr[0]
";
 680                 $tmpBranch= {};
 681                 for $tmpBranch (@tmpArr){
 682                     if ($1 eq $tmpBranch->{SF} ){
 683                         # 文件完全一致,需要合并信息
 684                         $FoundSameFile = 1;
 685                         # 取出已存在的branch数据
 686                         $branchHash = $tmpBranch;
 687                         #print "found same file:".$branchHash->{SF}.",".$tmpBranch->{SF}.",".$linecount."
";
 688                         #last;
 689                         #}else{
 690                         #print "same key but file diffrent: $1 ** $tmpBranch->{SF}
";
 691                     }
 692                 }
 693                 #}else{
 694                 #print "array len invalid($#tmpArr), (".$2.")
";
 695             }
 696             #}else{
 697             #print "new key
";
 698         }
 699         $branchHash->{SF}=$1;
 700         $branchHash->{fn}=$2;
 701     }elsif($fileLine =~ /^(BRDA:d+,d+,d+),(.+?)
*
*$/) {
 702         # BRDA:line,mod,condition = "0/1/...."
 703         if (($2 eq "-")||($2 eq "0")) {
 704             $tmp = 0;
 705         }else{
 706             $tmp = $2;
 707         }
 708 
 709         if ($FoundSameFile) {
 710             if (defined $branchHash->{$1}){
 711                 #print "same file update BRDA:".$1.","".$branchHash->{$1};
 712                 $branchHash->{$1} += $tmp;
 713                 #print "<=".$tmp."=>".$branchHash->{$1}.""
";
 714                 return;
 715             }
 716         }
 717         $branchHash->{$1} = $tmp;
 718     }elsif($fileLine =~ /^BRF:(d+)$/) {
 719         # 一个文件的所有分支信息收集完成
 720         @tmpArr=();
 721         if ( $FoundSameKey ){
 722             if ($FoundSameFile){
 723                 @tmpArr = @{$gLcovHash->{$branchHash->{fn}}};
 724                 for ( $idx = 0; $idx <= $#tmpArr; $idx ++){
 725                     $tmp = $tmpArr[$idx];
 726                     if ($tmp->{SF} eq $branchHash->{SF} ){
 727                         #print "same file, node updated:$idx,$tmp
";
 728                         $gLcovHash->{$branchHash->{fn}}[$idx] = $branchHash;
 729                         last;
 730                         #}else{
 731                         #print "diff file: $tmp->{SF},$branchHash->{SF}
";
 732                     }
 733                 }
 734             }else{
 735                 @tmpArr = @{$gLcovHash->{$branchHash->{fn}}};
 736                 push (@tmpArr,$branchHash);
 737                 $gLcovHash->{$branchHash->{fn}} = [ @tmpArr ];
 738                 #print "same key, new node pushed:@tmpArr
";
 739             }
 740         }else{
 741             push (@tmpArr,$branchHash);
 742             $gLcovHash->{$branchHash->{fn}} = [ @tmpArr ];
 743 
 744             #print "new key pushed:@tmpArr,$branchHash->{fn},$branchHash->{SF}
";
 745         }
 746         #print "------------
";
 747     }
 748 }
 749 
 750 sub merge_lcov_info{
 751     my $fileHandle;
 752     my $mergedLcovFile;
 753     my $buildPath = "";
 754 
 755     for ( $cp_idx = 0; $cp_idx < @gBuildCodePathArr; $cp_idx ++){
 756         $linecount = 0;
 757         # 遍历lcov的文件
 758         $buildPath=$gBuildCodePathArr[$cp_idx];
 759         $lcovFile=$gLcovFile."_".$cp_idx;
 760         print "-----------------------
";
 761         print " lcov parse build path: $buildPath
";
 762         system("lcov -q -c -d $buildPath -o $lcovFile -t fttest --ignore-errors gcov,source,graph --rc lcov_branch_coverage=1");
 763 
 764         if(-e $lcovFile) {
 765             open($fileHandle, "$lcovFile");
 766         }else {
 767             print "open $lcovFile fail.
";
 768             return;
 769         }
 770 
 771         # 读取lcov文件,添加或者合并源文件的覆盖数据
 772         print "merge_calc ---
";
 773         while(<$fileHandle>) {
 774             merge_calc($_);
 775         }
 776         close($fileHandle);
 777     }
 778 
 779     # 合并后的数据,进行输出
 780     open($mergedLcovFile, "> $gLcovFile");
 781 
 782     print "-----------------------
";
 783     print "export merged gLcov:$gLcovFile
";
 784     for $fn (keys %{$gLcovHash}){
 785         for $tmp (@{$gLcovHash->{$fn}}){
 786             print $mergedLcovFile("SF:$tmp->{SF}
");
 787             for $brdaKey (sort keys %{$tmp}){
 788                 if ($brdaKey eq "SF" ){
 789                     next;
 790                 }
 791                 print $mergedLcovFile("$brdaKey,$tmp->{$brdaKey}
");
 792             }
 793         }
 794     }
 795 
 796     close($mergedLcovFile);
 797 }
 798 
 799 sub changecovfile {
 800     my $fileHandle;
 801     my $filename = "";
 802     my $currfilename = "";
 803     my $lineNum = 0;
 804     my $lineLastNum = 0;
 805     my $linebegin = 1;
 806     my $condition;
 807     my $covflag;
 808     my $covcontext="";
 809     my $resultfile;
 810     my $totalbranch = 0;
 811     my $covbranch = 0;
 812 
 813     merge_lcov_info();
 814 
 815     if(-e $gLcovFile) {
 816         open($fileHandle, "$gLcovFile");
 817     }else {
 818         print "open $gLcovFile fail.
";
 819         return;
 820     }
 821 
 822     open($resultfile, "> $gCoverFile");
 823 
 824     while(<$fileHandle>) {
 825         #文件比较开始
 826         if($_ =~ /^SF:*+/(.+?[a-zA-Z])[^a-zA-Z]*$/) {
 827             $filename = $1;
 828         }
 829         if($_ =~ /^BRDA:(d+),(d+),(d+),(.+?)$/) {
 830             $lineNum = $1;
 831             $condition = $3;
 832 
 833             if ($linebegin == 1) {
 834                 $linebegin = 0;
 835                 $lineLastNum = $lineNum;
 836             }
 837 
 838             if (($4 eq "-")||($4 eq "0")) {
 839                 $covflag = " -";
 840             }else {
 841                 $covflag = " +";
 842             }
 843 
 844             if ($lineNum eq $lineLastNum) {
 845                 $covcontext = $covcontext.$covflag;
 846                 $totalbranch++;
 847                 if ($covflag eq " +") {
 848                     $covbranch++;
 849                 }
 850                 $currfilename = $filename;
 851             }else {
 852                 $Content = $currfilename.",".$lineLastNum.",".$totalbranch.",".$covbranch.",".$covcontext."
";
 853                 print $resultfile("$Content");
 854 
 855                 $covcontext = $covflag;
 856                 $lineLastNum = $lineNum;
 857                 $totalbranch = 1;
 858                 if ($covflag eq " +") {
 859                     $covbranch = 1;
 860                 }else {
 861                     $covbranch = 0;
 862                 }
 863             }
 864         }
 865     }
 866 
 867     $Content = $filename.",".$lineLastNum.",".$totalbranch.",".$covbranch.",".$covcontext."
";
 868     print $resultfile("$Content");
 869 
 870     close($fileHandle);
 871 
 872     close($resultfile);
 873     $Content = "";
 874 }
 875 
 876 sub ParseTestCasesStat{
 877     my $readFile;
 878 
 879     print "-----------------------
";
 880     if(defined $gTestcasesStat){
 881         if(-e $gTestcasesStat) {
 882             open($readFile, "$gTestcasesStat");
 883         }else {
 884             print $RecodResultFile("open $gTestcasesStat fail.
");
 885             return;
 886         }
 887         while(<$readFile>) {
 888             if($_ =~ /^all_cases:(d+) *$/) {
 889                 $all_stats = $1;
 890             }elsif ($_ =~ /^project_cases:(.*) $/){
 891                 $proj_stats = $1;
 892             }
 893         }
 894         print "Got TestCaseStats info: $all_stats . $proj_stats
";
 895         close($readFile);
 896     } else {
 897         print "gTestcaseStat not defined, stop parse testcases stat.
"
 898     }
 899 }
 900 
 901 
 902 sub GetYesterday(){
 903     my $ret= "";
 904     ($tmpY,$tmpM,$tmpD)=Add_Delta_Days(split("-",$gCurrDate),-1);
 905     $ret = $tmpY."-".$tmpM."-".$tmpD;
 906     print "Got Yestoday is ".$ret."
";
 907     return  $ret;
 908 }
 909 
 910 sub GetLastSunday(){
 911     my $delta=0;
 912     my $ret= "";
 913     #($tmpY,$tmpM,$tmpD) = split("-",$gCurrDate);
 914     $delta=Day_of_Week(split("-",$gCurrDate));
 915     ($tmpY,$tmpM,$tmpD)=Add_Delta_Days(split("-",$gCurrDate),-$delta);
 916     $ret = $tmpY."-".$tmpM."-".$tmpD;
 917     print "Got Last Sunday is ".$ret."
";
 918     return  $ret;
 919 }
 920 
 921 sub GetMonth1st(){
 922     my $ret= "";
 923     ($tmpY,$tmpM,$tmpD) = split("-",$gCurrDate);
 924     $ret = $tmpY."-".$tmpM."-1";
 925     print "Got MONTH first day is ".$ret."
";
 926     return  $ret;
 927 }
 928 
 929 sub GetYear1st(){
 930     my $ret= "";
 931     ($tmpY,$tmpM,$tmpD) = split("-",$gCurrDate);
 932     $ret = $tmpY."-1-1";
 933     print "Got YEAR first day is ".$ret."
";
 934     return  $ret;
 935 }
 936 
 937 sub GetDiffStartDate(){
 938     if ($gUpdateDateMethod eq "versionly") {
 939         return $gCurrDate; # no use return value
 940     }elsif ($gUpdateDateMethod eq "changely"){
 941         return $gCurrDate; # no use return value
 942     }elsif ($gUpdateDateMethod eq "daily"){
 943         return GetYesterday();
 944     }elsif ($gUpdateDateMethod eq "weekly"){
 945         return GetLastSunday();
 946     }elsif ($gUpdateDateMethod eq "monthly"){
 947         return GetMonth1st();
 948     }elsif ($gUpdateDateMethod eq "yearly"){
 949         return GetYear1st();
 950     }else{
 951         print "UpdateMethod is WRONG!!
";
 952         return 0;
 953     }
 954 }
 955 
 956 sub PrintDiffParams{
 957     my ($Param)=@_;
 958     print "-----------------------
";
 959     print "Projects: $gCodeVersion
GitBegin: $Param
GitTrunk: $gBranchVersion
DiffText: $gDifFile
CodePath: $gCodePath
";
 960     print "-----------------------
";
 961 }
 962 
 963 sub UpdateDiffFile {
 964     my $writefile;
 965 
 966     $gGitPrevDate = GetDiffStartDate();
 967 
 968     system("cd $gCodePath;git branch");
 969     
 970     if ($gUpdateDateMethod eq "versionly" ) {
 971         PrintDiffParams($gNodeBase);
 972         print "git diff $gNodeBase $gdiffId";
 973         system("cd $gCodePath;git diff -w -E $gNodeBase $gdiffId . > $gDifFile");
 974     }elsif ($gUpdateDateMethod eq "changely" ){
 975         system("cd $gCodePath;git diff -w -E origin/$gBranchVersion . > $gDifFile");
 976     }else{
 977         PrintDiffParams($gGitPrevDate);
 978         system("cd $gCodePath;git log --after="$gGitPrevDate" --pretty="%h" --date-order | tail -n1 | xargs -n1 -i git diff -w -E {} origin/$gBranchVersion . > $gDifFile");
 979     }
 980 
 981     #system("cd /home/brs/gitrepo/dev_21701/cov")
 982 }
 983 
 984 sub PutIgnorelinenoInHash {
 985     my $filename;
 986     if (defined $gIgnorelineno){
 987         my @IgnoreArr = split /;+/, $gIgnorelineno; 
 988 
 989         foreach(@IgnoreArr) {
 990             if ($_ =~ /^(.*)|(.*)$/) {
 991                 $filename = $1;
 992                 #print $filename."
";
 993                 my @LineArr = split /:+/, $2;
 994                 foreach (@LineArr) {
 995                     push @{$gIgnoreLineHash{$filename}},$_;
 996                 }
 997             }
 998         }
 999     }
1000 }
1001 
1002 sub IsKeyWordsPath {
1003     my ($filepath) = @_;
1004     my $flag = 0;
1005     my $keyword = "";
1006 
1007     foreach(@gKeyWordsArr) {
1008         $keyword = $_;
1009         if (($keyword eq "all")||($filepath =~ /$keyword/)) {
1010             $flag = 1;
1011             return $flag;
1012         }
1013     }
1014     #返回0说明没有命中关键字,需要忽略
1015     return $flag;
1016 }
1017 
1018 sub IsIgnore {
1019     my ($filename,$sectionname,$lineno) = @_;
1020     my $flag = 0;
1021 
1022     foreach(@gIgnoreArr) {
1023         if ($_ eq $filename) {
1024             $flag = 1;
1025             return $flag;
1026         }
1027     }
1028 
1029     foreach(@gIgnoreLineSection) {
1030         if ($_ eq $sectionname) {
1031             $flag = 1;
1032             return $flag;
1033         }
1034     }
1035 
1036     if(exists $gIgnoreLineHash{$filename}) {
1037         my @LineNoArray = @{$gIgnoreLineHash{$filename}};
1038         foreach(@LineNoArray) {
1039             if($lineno eq $_) {
1040                 #print $funcname."
";
1041                 $flag = 1;
1042                 return $flag;
1043             }
1044         }
1045     }
1046 
1047     return $flag;
1048 }
1049 
1050 sub ReadProjectCfgFromCiCfg
1051 {
1052     my $myversionfile;
1053     my $projectfilehandle; 
1054     my $version=""; 
1055 
1056     if(-e $gMyVersion)
1057     {
1058         open($myversionfile, "$gMyVersion");
1059     }else
1060     {
1061         print $RecodResultFile("open $gMyVersion fail.
");
1062         return;
1063     }
1064 
1065     while(<$myversionfile>)
1066     {
1067         if($_ =~ /^(.*)$/)
1068         {
1069             $version = $1;
1070         }
1071     }
1072     close($myversionfile);
1073 
1074     $gCiVersionCfgFile=$gCiHomePath.$gCiVersionCfgFile;
1075     if(-e $gCiVersionCfgFile)
1076     {
1077         open($projectfilehandle, "$gCiVersionCfgFile");
1078     }else
1079     {
1080         print $RecodResultFile("open $gCiVersionCfgFile fail.
");
1081         return;
1082     }
1083 
1084     while(<$projectfilehandle>)
1085     {
1086         if($_ =~ /^(.*) (.*) (.*) (.*) (.*)$/)
1087         {
1088             if ($1 eq $version)
1089             {
1090                 $gBranchVersion = $2;
1091                 $gCodeVersion = $4;
1092                 print
1093                 $1.
1094                 "----".$2.
1095                 "----".$3.
1096                 "----".$4.
1097                 "----".$5.
1098                 "
";
1099             }
1100         }
1101     }
1102     close($projectfilehandle);
1103 
1104 }
View Code
https://blog.csdn.net/yyw794/article/details/77963310

原因

Lcov(1.10及往后)默认是关闭 分支覆盖率的。
需要在参数中加入
--rc lcov_branch_coverage=1
才能使能。
(即修改lcovrc的配置信息)
解决措施

ENABLE_BRANCH="--rc lcov_branch_coverage=1"
lcov -c -d $TESTCASE_DIR -o $info_file  ${ENABLE_BRANCH} 1>/dev/null

另外,genhtml中要添加上面的参数

genhtml --branch-coverage  -o $COVERAGE_DIR $GENHTML_OPTIONS ${ENABLE_BRANCH} $info_file 1>/dev/null

你看看jenkins的单元测试的html输出,是否新增了分支覆盖率统计。

Executed 3 out of 3 tests: 3 tests pass.
run test succ
cp dbg succ
find: `bazel-out/local-opt/bin/modules/': No such file or directory
cp opt succ
Capturing coverage data from data/cov/objs
Found gcov version: 8.1.0
Scanning data/cov/objs for .gcda files ...
Found 150 data files in data/cov/objs
Processing data/proto/static_info.pb.pic.gcda
geninfo: ERROR: /apollo/data/cov/objs/modules/data/proto/static_info.pb.pic.gcno: reached unexpected end of file
============================
[ERROR] lcov failed!
(standard_in) 2: syntax error
[INFO] Took  seconds
============================

gcc -fprofile-arcs -ftest-coverage -o test test.c
lcov --directory . --capture --output-file test.info
genhtml -o results test.info

https://github.com/linux-test-project/lcov
lcov release version cannot resolve gcc 8. Use the github code and install 1.13.

google test lcov genhtml 产生覆盖率xml文件,去除不需要的文件(include),或者包含需要的(source)

https://blog.csdn.net/hanshuai584044490/article/details/83374617

问题:在产生了.gcno 和 .gcda两个文件后,使用lcov -c -d Debug/source/ -o Debug/coverage.info 产生中间文件coverage.info文件,然后用genhtml -o output/  Debug/coverage.info产生html文件,发现产生的index.xml文件包含了include,甚至/usr/*下的公共头文件,怎么去除这些不需要统计覆盖率的文件?
1。正向提取需要的文件:
//比如希望把source相关的路径提取出来
lcov --extract Debug/coverage.info '*source/*' -o Debug/finalresult.info
//然后产生的xml就包含所有source相关的文件
genhtml -o output/  Debug/finalresult.info
2。反向去除不需要的文件:
//比如希望去除UnitTest 和/usr/相关文件:
lcov --remove Debug/coverage.info '*UnitTest/*' '/usr/*' -o Debug/finalresult.info
//然后产生的xml就去除了UnitTest 和/usr/相关的文件
genhtml -o output/  Debug/finalresult.info
注意:lcov 不允许同时使用--extract  和  --remove

 
原文地址:https://www.cnblogs.com/cjyp/p/9993667.html