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 19 20import os 21import json 22import shutil 23import shlex 24import subprocess 25import sys 26 27# 子系统json目录 28SYSTEM_JSON = "build/subsystem_config.json" 29# 覆盖率gcda 30COVERAGE_GCDA_RESULTS = "test/localCoverage/codeCoverage/results/coverage/data/cxx" 31# 报告路径 32REPORT_PATH = "test/localCoverage/codeCoverage/results/coverage/reports/cxx" 33# llvm-gcov.sh 34LLVM_GCOV = "test/localCoverage/codeCoverage/llvm-gcov.sh" 35 36 37def _init_sys_config(): 38 sys.localcoverage_path = os.path.join(current_path, "..") 39 sys.path.insert(0, sys.localcoverage_path) 40 41 42def call(cmd_list, is_show_cmd=False, out=None, err=None): 43 return_flag = False 44 try: 45 if is_show_cmd: 46 print("execute command: {}".format(" ".join(cmd_list))) 47 if 0 == subprocess.call(cmd_list, shell=False, stdout=out, stderr=err): 48 return_flag = True 49 except Exception: 50 print("Error : command {} execute faild!".format(cmd_list)) 51 return_flag = False 52 return return_flag 53 54 55def execute_command(command, printflag=False): 56 try: 57 cmd_list = shlex.split(command) 58 coverage_log_path = os.path.join( 59 CODEPATH, "test/testfwk/developer_test/localCoverage", "coverage.log") 60 with open(coverage_log_path, 'a') as fd: 61 call(cmd_list, printflag, fd, fd) 62 except IOError: 63 print("Error: Exception occur in open err") 64 65 66def get_subsystem_config_info(): 67 subsystem_info_dic = {} 68 subsystem_config_filepath = os.path.join(CODEPATH, SYSTEM_JSON) 69 if os.path.exists(subsystem_config_filepath): 70 data = None 71 with open(subsystem_config_filepath, 'r') as f: 72 data = json.load(f) 73 if not data: 74 print("subsystem config file error.") 75 for value in data.values(): 76 subsystem_name = value.get('name') 77 subsystem_dir = value.get('dir') 78 subsystem_path = value.get('path') 79 subsystem_project = value.get('project') 80 subsystem_rootpath = os.path.join(CODEPATH, subsystem_path) 81 subsystem_info_dic[subsystem_name] = [ 82 subsystem_project, subsystem_dir, 83 subsystem_path, subsystem_rootpath 84 ] 85 return subsystem_info_dic 86 87 88def get_subsystem_name_list(): 89 subsystem_name_list = [] 90 subsystem_info_dic = get_subsystem_config_info() 91 for key in subsystem_info_dic.keys(): 92 subsystem_rootpath = subsystem_info_dic[key][3] 93 if os.path.exists(subsystem_rootpath): 94 subsystem_name_list.append(key) 95 return subsystem_name_list 96 97 98def get_subsystem_rootpath(subsystem_name): 99 subsystem_path = "" 100 subsystem_rootpath = "" 101 subsystem_info_dic = get_subsystem_config_info() 102 for key in subsystem_info_dic.keys(): 103 if key == subsystem_name: 104 subsystem_path = subsystem_info_dic[key][2] 105 subsystem_rootpath = subsystem_info_dic[key][3] 106 break 107 return subsystem_path, subsystem_rootpath 108 109 110def is_filterout_dir(ignore_prefix, check_path): 111 # 屏蔽列表 112 filter_out_list = ["unittest", "third_party", "test"] 113 for item in filter_out_list: 114 check_list = check_path[len(ignore_prefix):].split("/") 115 if item in check_list: 116 return True 117 return False 118 119 120def rm_unnecessary_dir(cov_path): 121 topdir = os.path.join(cov_path, "obj") 122 for root, dirs, files in os.walk(topdir): 123 if is_filterout_dir(topdir, root): 124 shutil.rmtree(root) 125 126 127def get_files_from_dir(find_path, postfix=None): 128 names = os.listdir(find_path) 129 file_list = [] 130 for fn in names: 131 if not os.path.isfile(os.path.join(find_path, fn)): 132 continue 133 if postfix is not None: 134 if fn.endswith(postfix): 135 file_list.append(fn) 136 else: 137 file_list.append(fn) 138 return file_list 139 140 141def get_gcno_files(cov_path, dir_name): 142 gcda_strip_path = dir_name[len(cov_path) + 1:] 143 gcda_list = get_files_from_dir(dir_name, ".gcda") 144 for file_name in gcda_list: 145 gcno_name = f"{os.path.splitext(file_name)[0]}.gcno" 146 gcno_path = os.path.join( 147 os.path.join(CODEPATH, OUTPUT), gcda_strip_path, gcno_name) 148 if os.path.exists(gcno_path): 149 if os.path.exists(gcno_path): 150 shutil.copy(gcno_path, dir_name) 151 else: 152 print("%s not exists!", gcno_path) 153 154 155def get_module_gcno_files(cov_path, dir_name): 156 for root, dirs, files in os.walk(dir_name): 157 get_gcno_files(cov_path, root) 158 159 160def gen_subsystem_trace_info(subsystem, data_dir, test_dir): 161 src_dir = os.path.join(CODEPATH, OUTPUT) 162 single_info_path = os.path.join( 163 CODEPATH, REPORT_PATH, "single_test", test_dir) 164 if not os.path.exists(single_info_path): 165 os.makedirs(single_info_path) 166 output_name = os.path.join( 167 CODEPATH, single_info_path, f"{subsystem}_output.info") 168 if not os.path.exists(src_dir): 169 print("Sours path %s not exist!", src_dir) 170 return 171 cmd = "lcov -c -b {} -d {} --gcov-tool {} -o {} --ignore-errors source,gcov".format( 172 src_dir, data_dir, os.path.join(CODEPATH, LLVM_GCOV), output_name) 173 print(f"single_test**{cmd}") 174 execute_command(cmd) 175 176 177def cut_info(subsystem, test_dir): 178 trace_file = os.path.join( 179 CODEPATH, REPORT_PATH, "single_test", 180 test_dir, f"{subsystem}_output.info") 181 output_name = os.path.join( 182 CODEPATH, REPORT_PATH, "single_test", 183 test_dir, f"{subsystem}_strip.info") 184 remove = r"'*/unittest/*' '*/third_party/*' 'sdk/android-arm64/*'" 185 if not os.path.exists(trace_file): 186 print("Error: trace file %s not exisit!", trace_file) 187 return 188 cmd = "lcov --remove {} {} -o {}".format(trace_file, remove, output_name) 189 execute_command(cmd) 190 191 192def gen_info(cov_path, test_dir, subsystem_list): 193 if len(subsystem_list) == 0: 194 return 195 for subsystem in subsystem_list: 196 (subsystem_path, subsystem_rootpath) = get_subsystem_rootpath(subsystem) 197 subsystem_data_abspath = os.path.join(cov_path, "obj", subsystem_path) 198 if not os.path.exists(subsystem_data_abspath): 199 continue 200 get_module_gcno_files(cov_path, subsystem_data_abspath) 201 gen_subsystem_trace_info(subsystem, subsystem_data_abspath, test_dir) 202 cut_info(subsystem, test_dir) 203 204 205def gen_all_test_info(subsystem_list): 206 cov_path = os.path.join(CODEPATH, COVERAGE_GCDA_RESULTS) 207 single_test_dir_list = [] 208 for root, dirs, files in os.walk(cov_path): 209 single_test_dir_list = dirs 210 break 211 for index, cur_test_dir in enumerate(single_test_dir_list): 212 cur_test_abs_dir = os.path.join(cov_path, cur_test_dir) 213 rm_unnecessary_dir(cur_test_abs_dir) 214 gen_info(cur_test_abs_dir, cur_test_dir, subsystem_list) 215 216 217def merge_subsystem_info_from_all_test(subsystem): 218 single_test_info_path = os.path.join(CODEPATH, REPORT_PATH, "single_test") 219 subsystem_info_list = [] 220 subsystem_info_name = f"{subsystem}_strip.info" 221 for root, dirs, files in os.walk(single_test_info_path): 222 if subsystem_info_name in files: 223 subsystem_info_path_tmp = os.path.join( 224 single_test_info_path, root, subsystem_info_name) 225 subsystem_info_list.append(subsystem_info_path_tmp) 226 if len(subsystem_info_list) == 0: 227 return 228 info_output_name = os.path.join( 229 CODEPATH, REPORT_PATH, subsystem_info_name) 230 cmd = "lcov -a {} -o {}".format( 231 " -a ".join(subsystem_info_list), info_output_name) 232 execute_command(cmd) 233 234 235def merge_all_test_subsystem_info(subsystem_list): 236 single_test_info_path = os.path.join( 237 CODEPATH, REPORT_PATH, "single_test") 238 if not os.path.exists(single_test_info_path): 239 print("Error: the single test info path %s not exist", 240 single_test_info_path) 241 return 242 for subsystem in subsystem_list: 243 print("Merging all %s info from test data......", subsystem) 244 merge_subsystem_info_from_all_test(subsystem) 245 246 247def merge_info(report_dir): 248 if not os.path.exists(report_dir): 249 print("Error: report dir %s not exist", report_dir) 250 return 251 subsystem_name_list = get_files_from_dir(report_dir, "_strip.info") 252 if len(subsystem_name_list) == 0: 253 print("Error: get subsytem trace files in \report directory failed.") 254 return 255 trace_file_list = [] 256 for subsystem in subsystem_name_list: 257 trace_file_name = os.path.join(report_dir, subsystem) 258 trace_file_list.append(trace_file_name) 259 cmd = "lcov -a {} -o {}".format( 260 " -a ".join(trace_file_list), os.path.join(report_dir, "ohos_codeCoverage.info")) 261 execute_command(cmd) 262 263 264def merge_all_subsystem_info(): 265 print("Merging all the sysbsystem trace files......") 266 merge_info(os.path.join(CODEPATH, REPORT_PATH)) 267 268 269def gen_html(cov_path): 270 tracefile = os.path.join(CODEPATH, REPORT_PATH, "ohos_codeCoverage.info") 271 if not os.path.exists(tracefile): 272 print("Error: the trace file %s not exist", tracefile) 273 return 274 cmd = "genhtml --branch-coverage --demangle-cpp -o {} -p {} --ignore-errors source {}".format( 275 os.path.join(CODEPATH, REPORT_PATH, "html"), CODEPATH, tracefile) 276 execute_command(cmd) 277 278 279def gen_final_report(cov_path): 280 print("Generating the html report......") 281 gen_html(cov_path) 282 283 284if __name__ == "__main__": 285 current_path = os.path.abspath(os.path.dirname(__name__)) 286 CODEPATH = current_path.split("/test/testfwk/developer_test")[0] 287 _init_sys_config() 288 from localCoverage.utils import get_product_name 289 # 编译生成的out路径 290 OUTPUT = "out/{}".format(get_product_name(CODEPATH)) 291 292 gen_all_test_info(subsystem_list=get_subsystem_name_list()) 293 merge_all_test_subsystem_info(subsystem_list=get_subsystem_name_list()) 294 merge_all_subsystem_info() 295 gen_final_report(os.path.join(CODEPATH, COVERAGE_GCDA_RESULTS)) 296