• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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