1#!/usr/bin/env python3 2# coding=utf-8 3 4# 5# Copyright (c) 2023 Huawei Device Co., Ltd. 6# Licensed under the Apache License, Version 2.0 (the "License"); 7# you may not use this file except in compliance with the License. 8# You may obtain a copy of the License at 9# 10# http://www.apache.org/licenses/LICENSE-2.0 11# 12# Unless required by applicable law or agreed to in writing, software 13# distributed under the License is distributed on an "AS IS" BASIS, 14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15# See the License for the specific language governing permissions and 16# limitations under the License. 17# 18 19import os 20import re 21import time 22import json 23import fcntl 24import platform 25import linecache 26import traceback 27from multiprocessing import Pool 28from lxml import html 29from selectolax.parser import HTMLParser 30 31 32class CoverageReportPath: 33 def __init__(self, report_path): 34 self.report_path = report_path 35 36 def gcov_file_generator(self): 37 """ 38 gcov文件生成器 39 """ 40 for root_path, _, files in os.walk(self.report_path): 41 for file in files: 42 if not file.endswith(".gcov.html"): 43 continue 44 file_path = os.path.join(root_path, file) 45 yield file_path 46 47 def modify_report_style(self): 48 """ 49 修改覆盖率报告css样式 50 """ 51 css_file_path = "" 52 for root_path, _, files in os.walk(self.report_path): 53 for file in files: 54 if file == "gcov.css": 55 css_file_path = os.path.join(root_path, file) 56 text = """ 57/* update */ 58span.linenumupdate, span.branchexecupdate, span.branchnoexecupdate, 59span.linecovupdate, span.linenocovupdate, span.branchcovupdate, 60span.branchnocovupdate 61{ 62 background-color:#BBBBBB; 63}""" 64 with open(css_file_path, "a+", encoding="utf-8") as file: 65 file.write(text) 66 67 def get_statistic_path(self, gcov_file_path: str): 68 """ 69 根据gcov.html路径和统计等级获取统计报告路径 70 """ 71 file_name_list = ["index.html", "index-sort-b.html", 72 "index-sort-f.html", "index-sort-l.html"] 73 index_path_list = [ 74 os.path.normcase(os.path.join(os.path.dirname(gcov_file_path), file_name)) 75 for file_name in file_name_list 76 ] 77 out_path_list = [ 78 os.path.normcase(os.path.join(self.report_path, file_name)) 79 for file_name in file_name_list 80 ] 81 index_path_list.extend(out_path_list) 82 return index_path_list 83 84 85class KeywordRegistration: 86 def __init__(self, report_path): 87 self.report_path = report_path 88 self.keyword_file_path = os.path.normcase( 89 os.path.join(os.path.dirname(__file__), "keyword.json")) 90 91 def get_keyword_info(self): 92 """ 93 获取报备关键字信息 94 """ 95 try: 96 with open(self.keyword_file_path, "r") as file: 97 keyword_dict = json.load(file) 98 keyword_list = keyword_dict.get("KEYWORD") 99 return keyword_list 100 except (FileNotFoundError, AttributeError, FileExistsError): 101 print(f"获取报备过滤关键字报错") 102 103 @staticmethod 104 def get_coverage_content(file_path): 105 """ 106 获取覆盖率文件内容 107 """ 108 if not os.path.exists(file_path): 109 return 110 with open(file_path, "r", encoding="utf-8") as file: 111 content = file.read() 112 return content 113 114 @staticmethod 115 def get_tag(content, line): 116 start_index = content.find(f'<a name="{line}"') 117 end_index = content.find(f'<a name="{int(line) + 1}"') 118 tag = content[start_index:end_index - 1] 119 return tag 120 121 @staticmethod 122 def get_source_code(tag): 123 etree = html.etree 124 parser = etree.HTMLParser(encoding="utf-8") 125 parser_obj = etree.HTML(tag, parser=parser) 126 source_code = parser_obj.xpath("//span[@class='lineNoCov' or " 127 "@class='lineCov' or " 128 "@class='linecovupdate' or" 129 "@class='linenocovupdate']/text()") 130 if not source_code: 131 index = tag.find(":") 132 source_code = tag[index + 1:].split("</a>")[0] 133 134 if source_code: 135 source_code = "".join(source_code) 136 return source_code 137 138 @staticmethod 139 def update_tag(tag: str): 140 replace_item_list = ["lineNum", "branchNoCov", "branchCov", "lineCov", 141 "branchNoExec", "lineNoCov", "branchExec"] 142 143 for item in replace_item_list: 144 if item in tag: 145 replace_item = (item + "Update").lower() 146 tag = tag.replace(item, replace_item) 147 return tag 148 149 def get_coverage_lines_by_branch(self, file_path, content=None): 150 """ 151 获取覆盖率报告中的所有的if分支行号 152 """ 153 if not content: 154 content = self.get_coverage_content(file_path) 155 if not content: 156 return 157 _, file_name = os.path.split(file_path) 158 branch_line_list = re.findall( 159 r'''<a name="(\d+).*?Branch.*? if \(| 160 <a name="(\d+).*?Branch.*? if\(''', content) 161 162 if branch_line_list: 163 branch_line_list = [int(line_tuple[0]) if line_tuple[0] else 164 int(line_tuple[1]) for line_tuple in branch_line_list] 165 return branch_line_list 166 167 def get_coverage_lines_by_keyword(self, keyword, content): 168 """ 169 获取关键字在覆盖率报告中的行号 170 """ 171 if "&" in keyword: 172 keyword = keyword.replace("&", "") 173 origin_keyword = keyword 174 if keyword.endswith("("): 175 keyword = keyword.replace("(", "") 176 keyword_line_list = re.findall( 177 rf'<a name="(\d+).*?[ .;!:()]{keyword}[ .;!:()&]', content) 178 else: 179 keyword_line_list = re.findall( 180 rf'<a name="(\d+).*?[ .;!:()]{keyword}[ .;!:)&]', content) 181 182 if keyword_line_list: 183 keyword_line_list = [int(line) for line in keyword_line_list] 184 keyword_branch_list = [] 185 get_tag = self.get_tag 186 keyword_branch_list_append = keyword_branch_list.append 187 keyword_line_list_remove = keyword_line_list.remove 188 for line in keyword_line_list: 189 tag_html = get_tag(content, line) 190 if origin_keyword not in tag_html: 191 keyword_branch_list_append(line) 192 if 'title="Branch' not in tag_html: 193 continue 194 if "switch (" in tag_html or "switch(" in tag_html: 195 keyword_branch_list_append(line) 196 elif "while (" in tag_html or "while(" in tag_html: 197 keyword_branch_list_append(line) 198 elif "for (" in tag_html or "for(" in tag_html: 199 keyword_branch_list_append(line) 200 elif "do {" in tag_html or "do{" in tag_html: 201 keyword_branch_list_append(line) 202 for key in keyword_branch_list: 203 keyword_line_list_remove(key) 204 return keyword_line_list 205 206 def code_body_judge(self, line, content): 207 """ 208 全量报备按行获取覆盖率报告源码 209 """ 210 func_body_tag_list = [] 211 update_func_body_tag_list = [] 212 func_body_tag_list_append = func_body_tag_list.append 213 update_func_body_tag_list_append = update_func_body_tag_list.append 214 get_tag = self.get_tag 215 update_tag = self.update_tag 216 tag = get_tag(content, line) 217 if "{" not in tag: 218 return func_body_tag_list, update_func_body_tag_list 219 220 braces_sub = 1 221 if "{" not in tag: 222 braces_sub = 0 223 next_line = int(line) + 1 224 branch_braces_sub = count = 0 225 sub_brace_start_status = sub_brace_end_status = False 226 while braces_sub: 227 count += 1 228 if count > 200: 229 return [], [] 230 next_tag = get_tag(content, str(next_line)) 231 func_body_tag_list_append(next_tag) 232 if "{" in next_tag: 233 if branch_braces_sub: 234 branch_braces_sub += 1 235 braces_sub += 1 236 if "}" in next_tag: 237 if branch_braces_sub: 238 branch_braces_sub -= 1 239 braces_sub -= 1 240 if 'title="Branch' in next_tag: 241 branch_braces_sub += 1 242 sub_brace_start_status = True 243 if not branch_braces_sub and \ 244 (sub_brace_start_status == sub_brace_end_status): 245 next_tag = update_tag(next_tag) 246 if not branch_braces_sub and sub_brace_start_status: 247 sub_brace_end_status = True 248 update_func_body_tag_list_append(next_tag) 249 next_line += 1 250 return func_body_tag_list, update_func_body_tag_list 251 252 def get_line_funcname(self, branch_line, content): 253 """ 254 获取行号源码所在函数的函数名 255 """ 256 function_name = "" 257 previous_line = int(branch_line) 258 loop_count = 0 259 get_tag = self.get_tag 260 try: 261 while not function_name: 262 loop_count += 1 263 if loop_count > 200: 264 return 265 previous_line -= 1 266 tag = get_tag(content, previous_line) 267 tag_text = HTMLParser(tag).text() 268 if tag_text[39:].strip().startswith("{"): 269 left_parentheses_count = right_parentheses_count = 0 270 child_count = 0 271 while previous_line: 272 child_count += 1 273 if child_count > 200: 274 return 275 previous_line -= 1 276 html_text = get_tag(content, previous_line) 277 source_code = HTMLParser(html_text).text()[39:].strip() 278 279 left_parentheses_count += source_code.count("(") 280 right_parentheses_count += source_code.count(")") 281 if not left_parentheses_count == right_parentheses_count: 282 continue 283 if " operator" in source_code: 284 class_name_list = re.findall(r'\((.*?)\)', source_code) 285 if class_name_list: 286 function_name_str = class_name_list[0] 287 if not function_name_str: 288 return 289 function_name = function_name_str.split()[-1] 290 return function_name 291 function_name_list = re.findall(r' (.*?)\(', source_code) 292 if function_name_list: 293 function_name_str = function_name_list[0] 294 if not function_name_str: 295 return 296 function_name = function_name_str.split()[-1] 297 return function_name 298 except (OSError, IndexError, TypeError) as error: 299 print(f"覆盖率报告{branch_line}行获取函数名报错, error:{error}", 300 traceback.format_exc()) 301 302 @staticmethod 303 def get_branch_line_list(keyword_line: int, branch_line_list: list): 304 """ 305 获取大于关键字行号的所有分支行号 306 """ 307 if keyword_line in branch_line_list: 308 index = branch_line_list.index(keyword_line) 309 branch_line_list = branch_line_list[index:] 310 else: 311 for line in branch_line_list: 312 if line > keyword_line: 313 index = branch_line_list.index(line) 314 branch_line_list = branch_line_list[index:] 315 break 316 return branch_line_list 317 318 @staticmethod 319 def get_keyword_judge_char(keyword, keyword_source_code): 320 """ 321 获取关键字替代字符 322 """ 323 if "&" in keyword: 324 keyword = keyword.replace("&", "<") 325 326 keyword_index = keyword_source_code.find(keyword) 327 if keyword_index == -1: 328 return 329 330 try: 331 keyword_code = keyword_source_code[:keyword_index + len(keyword)] 332 if " = " in keyword_code: 333 judge_key = keyword_code.split(" = ")[0].split()[-1] 334 else: 335 bracket_index = keyword_code.find("(") 336 bracket_code = keyword_code[:bracket_index] 337 judge_key = bracket_code.split()[-1] 338 return judge_key 339 except (IndexError, ValueError): 340 print("获取关键字替代字符失败") 341 342 @staticmethod 343 def get_branch_data_by_tag(tag_html: str, symbol_status=None): 344 """ 345 根据前端标签获取分支数据 346 """ 347 if symbol_status: 348 key = r"#+\-*" 349 else: 350 key = r"#+\-" 351 branch_line_list = re.findall(rf"> ([{key}]) </span>", tag_html) 352 353 return branch_line_list 354 355 @staticmethod 356 def get_judge_condition_index(judge_key: str, source_code: str): 357 """ 358 获取判断条件索引 359 """ 360 keyword_index_list = [] 361 keyword_index_list_append = keyword_index_list.append 362 363 condition_str_list = re.split(rf"\|\||&&", source_code) 364 for index, code_str in enumerate(condition_str_list): 365 if judge_key in code_str: 366 keyword_index_list_append(index) 367 return keyword_index_list, condition_str_list 368 369 @staticmethod 370 def update_source_code_tag(html_tag: str): 371 replace_item_list = ["lineNum", "lineCov", "lineNoCov"] 372 373 for item in replace_item_list: 374 if item in html_tag: 375 replace_item = (item + "Update").lower() 376 html_tag = html_tag.replace(item, replace_item) 377 378 return html_tag 379 380 def get_break_line_tag(self, content, origin_branch_html, branch_line): 381 """ 382 获取分支换行的判断条件源码tag 383 """ 384 get_tag = self.get_tag 385 left_brace_exist = False 386 line_break = loop_count = 0 387 while not left_brace_exist: 388 if loop_count > 10: 389 break 390 line_break += 1 391 origin_branch_html = os.path.join(origin_branch_html, "\n") 392 next_line_tag = get_tag(content, branch_line + line_break) 393 if "{" in next_line_tag: 394 left_brace_exist = True 395 origin_branch_html += next_line_tag 396 loop_count += 1 397 return origin_branch_html 398 399 @staticmethod 400 def modify_tag_style(tag, rate): 401 """ 402 修改标签样式 403 """ 404 if 75 <= rate < 90: 405 tag = tag.replace("headerCovTableEntryLo", "headerCovTableEntryMed") 406 tag = tag.replace("coverPerLo", "coverPerMed") 407 tag = tag.replace("coverNumLo", "coverNumMed") 408 elif rate >= 90: 409 tag = tag.replace("headerCovTableEntryLo", "headerCovTableEntryHi") 410 tag = tag.replace("headerCovTableEntryMed", "headerCovTableEntryHi") 411 tag = tag.replace("coverPerLo", "coverPerHi") 412 tag = tag.replace("coverNumLo", "coverNumHi") 413 tag = tag.replace("coverPerMed", "coverPerHi") 414 tag = tag.replace("coverNumMed", "coverNumHi") 415 return tag 416 417 def update_coverage_ratio_tag(self, file_path): 418 """ 419 修改覆盖率比率数据 420 """ 421 with open(file_path, "r", encoding="utf-8") as coverage_file: 422 content = coverage_file.read() 423 424 covered_nums = len(re.findall(r"> ([+]) </span>", content)) 425 branch_total = len(re.findall(r"> ([+\-#]) </span>", content)) 426 427 line = 0 428 start_line = 1 429 content_list = content.splitlines() 430 for line_text in content_list: 431 if '<td class="headerItem">Branches:</td>' in line_text: 432 line = start_line 433 break 434 start_line += 1 435 linecache.clearcache() 436 coverage_tag = linecache.getline(file_path, line) 437 covered_tag = linecache.getline(file_path, line + 1) 438 coverage_total_tag = linecache.getline(file_path, line + 2) 439 try: 440 origin_hit = int(re.findall(r"(\d+)", covered_tag)[0]) 441 origin_total = int(re.findall(r"(\d+)", coverage_total_tag)[0]) 442 coverage_rate_tag = linecache.getline(file_path, line + 3) 443 replace_tag = coverage_tag + covered_tag + coverage_total_tag + \ 444 coverage_rate_tag 445 if origin_total - branch_total == 0 and origin_hit - covered_nums == 0: 446 return 447 if int(branch_total) == 0: 448 coverage = 0.0 449 else: 450 coverage = round(int(covered_nums) / int(branch_total) * 100, 1) 451 452 origin_rate = re.findall(r"(\d+.\d+)", coverage_rate_tag)[0] 453 update_tag = coverage_tag + covered_tag.replace( 454 str(origin_hit), str(covered_nums)) + \ 455 coverage_total_tag.replace(str(origin_total), 456 str(branch_total)) + \ 457 coverage_rate_tag.replace(origin_rate, str(coverage)) 458 459 update_tag = self.modify_tag_style(update_tag, coverage) 460 if replace_tag in content: 461 content = content.replace(replace_tag, update_tag) 462 463 with open(file_path, "w", encoding="utf-8") as file: 464 file.write(content) 465 466 # 修改数据统计页面 467 hit_shield_num = origin_hit - covered_nums 468 total_shield_num = origin_total - branch_total 469 self.update_statistic(file_path, hit_shield_num, total_shield_num) 470 except (IndexError, TypeError, FileNotFoundError): 471 print("修改分支数据失败") 472 473 def update_statistic(self, file_path, hit_shield_num, total_shield_num): 474 """ 475 修改覆盖率分支数据 476 """ 477 index_path_list = CoverageReportPath(self.report_path).get_statistic_path(file_path) 478 for index_path in index_path_list: 479 if not os.path.exists(index_path): 480 continue 481 482 with open(index_path, "r", encoding="utf-8") as coverage_file: 483 fcntl.flock(coverage_file.fileno(), fcntl.LOCK_EX) 484 content = coverage_file.read() 485 486 file_dir, file_name = os.path.split(file_path) 487 if os.path.normcase(file_dir) not in os.path.normcase(index_path): 488 if platform.system() == "Windows": 489 judge_item = file_dir.replace(self.report_path + "\\", "") 490 judge_item = ">" + judge_item.replace("\\", "/") + "</a>" 491 else: 492 judge_item = file_dir.replace(self.report_path + "/", "") 493 judge_item = ">" + judge_item + "</a>" 494 else: 495 judge_item = ">" + file_name.replace(".gcov.html", "") 496 497 start_line = 1 498 line = tag_line = 0 499 content_list = content.splitlines() 500 tmp = '<td class="headerItem">Branches:</td>' 501 for line_text in content_list: 502 if not line and tmp in line_text: 503 line = start_line 504 if judge_item in line_text: 505 tag_line = start_line 506 break 507 start_line += 1 508 try: 509 # total statistic modify 510 linecache.clearcache() 511 coverage_head_tag = linecache.getline(index_path, line) 512 origin_hit_tag = linecache.getline(index_path, line + 1) 513 origin_hit_num = int(re.findall(r"(\d+)", origin_hit_tag)[0]) 514 origin_total_tag = linecache.getline(index_path, line + 2) 515 origin_total_num = int(re.findall(r"(\d+)", origin_total_tag)[0]) 516 origin_rate_tag = linecache.getline(index_path, line + 3) 517 origin_rate = re.findall(r"(\d+.\d+)", origin_rate_tag)[0] 518 replace_tag = coverage_head_tag + origin_hit_tag + \ 519 origin_total_tag + origin_rate_tag 520 521 # file branch modify 522 no_change_file_tag = "" 523 for i in range(8): 524 no_change_file_tag += linecache.getline(index_path, tag_line + i) 525 file_rate_tag = linecache.getline(index_path, tag_line + 8) 526 file_covered_tag = linecache.getline(index_path, tag_line + 9) 527 file_tag = no_change_file_tag + file_rate_tag + file_covered_tag 528 origin_file_covered_num, origin_file_total_num = map( 529 int, re.findall(r"(\d+)", file_covered_tag)) 530 if origin_file_total_num: 531 origin_file_rate = re.findall(r"(\d+.\d+)", file_rate_tag)[0] 532 else: 533 # 不存在覆盖率 534 origin_file_rate = "-" 535 head_hit_num = origin_hit_num - hit_shield_num 536 head_total_num = origin_total_num - total_shield_num 537 if head_total_num == 0: 538 rate = 0.0 539 else: 540 rate = round(head_hit_num / head_total_num * 100, 1) 541 file_hit_num = origin_file_covered_num - hit_shield_num 542 file_total_num = origin_file_total_num - total_shield_num 543 if file_total_num == 0: 544 file_rate = 0.0 545 else: 546 file_rate = round(file_hit_num / file_total_num * 100, 1) 547 update_tag = coverage_head_tag + origin_hit_tag.replace( 548 str(origin_hit_num), str(head_hit_num)) + \ 549 origin_total_tag.replace(str(origin_total_num), 550 str(head_total_num)) + \ 551 origin_rate_tag.replace(origin_rate, str(rate)) 552 553 update_tag = self.modify_tag_style(update_tag, rate) 554 555 update_branch_tag = file_rate_tag.replace( 556 origin_file_rate, str(file_rate)) + \ 557 file_covered_tag.replace( 558 str(origin_file_covered_num) + " / " + 559 str(origin_file_total_num), str(file_hit_num) + " / " + 560 str(file_total_num)) 561 562 update_branch_tag = self.modify_tag_style(update_branch_tag, file_rate) 563 update_branch_tag = no_change_file_tag + update_branch_tag 564 if replace_tag in content: 565 content = content.replace(replace_tag, update_tag) 566 if file_tag in content: 567 content = content.replace(file_tag, update_branch_tag) 568 with open(index_path, "w", encoding="utf-8") as file: 569 file.write(content) 570 fcntl.flock(file.fileno(), fcntl.LOCK_UN) 571 time.sleep(1) 572 except (IndexError, TypeError, FileNotFoundError): 573 print("修改分支统计数据出错") 574 575 def _check_if_branch_line(self, judge_key, sub_branch_line_list, 576 key_line, content, function_name): 577 """ 578 确定if分支行号 579 """ 580 if_branch_line = None 581 for branch_line in sub_branch_line_list: 582 if branch_line == key_line: 583 if_branch_line = key_line 584 break 585 # 获取分支行所在函数名 586 branch_function_name = self.get_line_funcname( 587 branch_line, content) 588 # 关键字范围只在关键字所在函数之内 589 branch_line_tag = self.get_tag(content, branch_line) 590 try: 591 if "{" not in branch_line_tag: 592 branch_line_tag = self.get_break_line_tag( 593 content, branch_line_tag, branch_line) 594 branch_line_source_code = self.get_source_code( 595 branch_line_tag) 596 if function_name == branch_function_name: 597 if judge_key in branch_line_source_code: 598 if_branch_line = branch_line 599 break 600 else: 601 break 602 except (ValueError, KeyError): 603 print("获取关键字if分支行报错", traceback.format_exc()) 604 605 return if_branch_line 606 607 @staticmethod 608 def _branch_replace(branch): 609 """ 610 分支符号替换 611 """ 612 if branch == "#": 613 branch = "> # <" 614 elif branch == "+": 615 branch = "> + <" 616 elif branch == "*": 617 branch = "> * <" 618 else: 619 branch = "> - <" 620 return branch 621 622 @staticmethod 623 def _single_condition_modify_html(branch_html, branch_list): 624 """ 625 单条件修改代码块html 626 """ 627 line_item = '<span class="lineNum"> </span>' 628 line_feed_index = branch_html.find(line_item) 629 if line_feed_index == -1: 630 if "+" in branch_list: 631 update_branch_tag = branch_html.replace("> - <", "> <") 632 update_branch_tag = update_branch_tag.replace("> # <", "> <") 633 else: 634 try: 635 first_branch = branch_list[0] 636 first_branch = "> " + first_branch + " <" 637 first_branch_index = branch_html.find(first_branch) 638 branch_tag = branch_html[:first_branch_index + 5] 639 update_branch_tag = branch_html[first_branch_index + 5:] 640 update_branch_tag = update_branch_tag.replace("> - <", "> <") 641 update_branch_tag = update_branch_tag.replace("> # <", "> <") 642 update_branch_tag = branch_tag + update_branch_tag 643 except ValueError: 644 return 645 else: 646 line_feed_index = branch_html.find(line_item) 647 update_branch_tag = branch_html[:line_feed_index + len(line_item) + 1] 648 if "-" not in branch_list and "+" not in branch_list: 649 del_count = update_branch_tag.count("> # <") 650 update_branch_tag = update_branch_tag.replace("> # <", "> <", del_count - 1) 651 else: 652 update_branch_tag = update_branch_tag.replace("> - <", "> <") 653 update_branch_tag = update_branch_tag.replace("> # <", "> <") 654 branch_tag = branch_html[line_feed_index + len(line_item) + 1:] 655 line_feed_index = branch_tag.find(line_item) 656 if line_feed_index == -1: 657 branch_tag = branch_tag.replace("> - <", "> <") 658 branch_tag = branch_tag.replace("> # <", "> <") 659 update_branch_tag += branch_tag 660 else: 661 loop_count = 0 662 while line_feed_index + 1: 663 loop_count += 1 664 if loop_count > 200: 665 continue 666 try: 667 update_branch_tag += branch_tag[:line_feed_index + len(line_item) + 1] 668 update_branch_tag = update_branch_tag.replace("> - <", "> <") 669 update_branch_tag = update_branch_tag.replace("> # <", "> <") 670 branch_tag = branch_tag[line_feed_index + len(line_item) + 1:] 671 line_feed_index = branch_tag.find(line_item) 672 except ValueError: 673 return 674 675 branch_tag = branch_tag.replace("> - <", "> <") 676 update_branch_tag = update_branch_tag.replace("> # <", "> <") 677 update_branch_tag += branch_tag 678 return update_branch_tag 679 680 def _multi_condition_modify_html(self, branch_html, branch_length, 681 condition_str_list, judge_index_list): 682 """ 683 多条件修改代码块html 684 """ 685 line_item = '<span class="lineNum"> </span>' 686 if branch_length % len(condition_str_list): 687 line_feed_index = branch_html.find(line_item) 688 update_branch_tag = branch_html[:line_feed_index] 689 update_branch_tag = update_branch_tag.replace("> - <", "> <") 690 branch_html = branch_html[line_feed_index:] 691 loop_count = 0 692 while line_feed_index + 1: 693 loop_count += 1 694 if loop_count > 200: 695 continue 696 line_feed_index = branch_html.count(line_item) 697 if line_feed_index > 1: 698 try: 699 line_feed_length = len(line_item) 700 branch_tag_before = branch_html[:line_feed_length] 701 branch_html = branch_html[line_feed_length:] 702 line_feed_index = branch_html.find(line_item) 703 branch_tag_after = branch_html[:line_feed_index] 704 branch_tag_after = branch_tag_after.replace("> - <", "> <") 705 branch_tag = branch_tag_before + branch_tag_after 706 except ValueError: 707 return 708 else: 709 branch_tag = branch_html 710 branch_tag = branch_tag.replace("> - <", "> <") 711 # 不再换行,索引为-1 712 line_feed_index = -1 713 714 update_branch_tag += branch_tag 715 if line_feed_index == -1: 716 branch_html = "" 717 else: 718 branch_html = branch_html[line_feed_index:] 719 if branch_html != "": 720 branch_html = branch_html.replace("> - <", "> <") 721 update_branch_tag += branch_html 722 else: 723 branch_list = self.get_branch_data_by_tag(branch_html, True) 724 update_branch_tag = "" 725 end_count = -1 726 try: 727 for index in judge_index_list: 728 branch_data = branch_list[:(index + 1) * 2] 729 # 要修改的分支数据列表长度 730 branch_data_length = len(branch_data) 731 change_status = False 732 for count, branch in enumerate(branch_data, 1): 733 if count <= end_count: 734 continue 735 736 end_count = count 737 branch = self._branch_replace(branch) 738 end_index = branch_html.find(branch) 739 branch_tag = branch_html[:end_index + 5] 740 if branch_data_length - count in [0, 1]: 741 if change_status: 742 continue 743 if branch == "> # <": 744 change_status = True 745 branch_tag = branch_tag.replace("> # <", "> * <") 746 elif branch == "> - <": 747 change_status = True 748 branch_tag = branch_tag.replace("> - <", "> * <") 749 update_branch_tag += branch_tag 750 branch_html = branch_html[end_index + 5:] 751 except (ValueError, TypeError): 752 return 753 update_branch_tag += branch_html 754 return update_branch_tag 755 756 def judge_branch_exists(self, file_path): 757 """ 758 判断报告是否存在分支 759 """ 760 content = self.get_coverage_content(file_path) 761 branch_total = len(re.findall(r"> ([+\-#]) </span>", content)) 762 if branch_total: 763 return True 764 else: 765 return False 766 767 def modify_branch(self, file_path, keyword_list): 768 """ 769 html报告分支屏蔽修改 770 """ 771 branch_line_list = self.get_coverage_lines_by_branch(file_path) 772 if not branch_line_list: 773 return 774 775 branch_line_list.sort() 776 no_change_content = self.get_coverage_content(file_path) 777 for keyword in keyword_list: 778 content = self.get_coverage_content(file_path) 779 keyword_line_list = self.get_coverage_lines_by_keyword(keyword, content) 780 if not keyword_line_list: 781 continue 782 for key_line in keyword_line_list: 783 key_html = self.get_tag(content, key_line) 784 if not key_html or "LOG" in key_html: 785 continue 786 787 function_name = self.get_line_funcname(key_line, content) 788 sub_branch_line_list = self.get_branch_line_list( 789 key_line, branch_line_list) 790 keyword_source_code = self.get_source_code(key_html) 791 if not all([function_name, keyword_source_code, 792 sub_branch_line_list]): 793 continue 794 795 judge_key = keyword 796 if 'title="Branch' not in key_html: 797 judge_key = self.get_keyword_judge_char( 798 keyword, keyword_source_code) 799 if "*" in judge_key: 800 judge_key = judge_key.replace("*", "") 801 if "&" in judge_key: 802 judge_key = judge_key.replace("&", "") 803 if_branch_line = self._check_if_branch_line( 804 judge_key, sub_branch_line_list, key_line, 805 content, function_name) 806 807 if not if_branch_line: 808 continue 809 810 origin_branch_html = self.get_tag(content, if_branch_line) 811 branch_html = origin_branch_html 812 if "{" not in origin_branch_html: 813 origin_branch_html = self.get_break_line_tag( 814 content, origin_branch_html, if_branch_line) 815 branch_html = origin_branch_html 816 top_source_code = self.get_source_code(branch_html) 817 no_change_branch_html = self.get_tag( 818 no_change_content, if_branch_line) 819 branch_list = self.get_branch_data_by_tag(no_change_branch_html) 820 if not branch_list: 821 continue 822 if "#" not in branch_list and "-" not in branch_list: 823 continue 824 branch_tag_data = self.get_branch_data_by_tag(branch_html, True) 825 if len(branch_tag_data) <= 1: 826 continue 827 if len(branch_list) == 2: 828 if "-" in branch_list: 829 update_branch_tag = branch_html.replace("> - <", "> <") 830 else: 831 update_branch_tag = branch_html.replace("> # <", "> <", 1) 832 else: 833 branch_length = len(branch_list) 834 judge_index_list, condition_str_list = self.\ 835 get_judge_condition_index(judge_key, top_source_code) 836 if not len(judge_index_list): 837 continue 838 if len(condition_str_list) == 1: 839 update_branch_tag = self._single_condition_modify_html( 840 branch_html, branch_list) 841 else: 842 update_branch_tag = self._multi_condition_modify_html( 843 branch_html, branch_length, condition_str_list, 844 judge_index_list) 845 if not update_branch_tag: 846 return 847 848 update_branch_tag = self.update_source_code_tag( 849 update_branch_tag) 850 content = content.replace(origin_branch_html, update_branch_tag) 851 source_code_tag_list, update_source_code_tag_list = self.\ 852 code_body_judge(int(if_branch_line), content) 853 if source_code_tag_list: 854 source_code_tag_html = "\n".join(source_code_tag_list) 855 update_source_code_tag_html = "\n".join( 856 update_source_code_tag_list) 857 content = content.replace( 858 source_code_tag_html, update_source_code_tag_html) 859 with open(file_path, "w", encoding="utf-8") as new_html: 860 new_html.write(content) 861 862 content = self.get_coverage_content(file_path) 863 content = content.replace('> * </span>', '> </span>') 864 with open(file_path, "w", encoding="utf-8") as new_html: 865 new_html.write(content) 866 867 def keyword_registration(self, file_path, keyword_list): 868 """ 869 报备 870 """ 871 self.modify_branch(file_path, keyword_list) 872 873 # 修改覆盖率数据 874 self.update_coverage_ratio_tag(file_path) 875 return True 876 877 def multiprocessing_registration(self): 878 """ 879 多进程关键字报备 880 """ 881 keyword_list = self.get_keyword_info() 882 if not keyword_list: 883 return 884 885 # 创建报告路径生成器 886 report_instance = CoverageReportPath(self.report_path) 887 # 修改css文件 888 report_instance.modify_report_style() 889 # 创建报告路径生成器 890 report_generator = report_instance.gcov_file_generator() 891 # 获取关键字 892 keyword_registration = self.keyword_registration 893 894 pool = Pool(10) 895 apply_async = pool.apply_async 896 while True: 897 file_path = next(report_generator, None) 898 if not file_path: 899 break 900 901 # 关键字报备 902 apply_async(keyword_registration, args=(file_path, keyword_list)) 903 904 pool.close() 905 pool.join() 906 907 908def main(report_path): 909 print("*" * 50, "报备开始", "*" * 50) 910 manager = KeywordRegistration(report_path) 911 start_time = time.time() 912 manager.multiprocessing_registration() 913 end_time = time.time() 914 times = round(end_time - start_time, 3) 915 print("*" * 50, "报备结束", "*" * 50, "耗时:", times) 916 917 918if __name__ == '__main__': 919 current_path = os.getcwd() 920 home_path = current_path.split("/test/testfwk/developer_test")[0] 921 developer_path = os.path.join(home_path, "test/testfwk/developer_test") 922 html_path = os.path.join(developer_path, "localCoverage/codeCoverage/results/coverage/reports/cxx/html") 923 main(html_path) 924